﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration.Provider;
using Barbar.MapReport.DataSource.Resources;
using System.Collections;
using System.Globalization;
using System.Collections.ObjectModel;
using Barbar.MapReport.DataSource.Query;

namespace Barbar.MapReport.DataSource {
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1010:CollectionsShouldImplementGenericInterface")]
  public class RegionProviderCollection : ProviderCollection {
    private Hashtable m_RegionById = new Hashtable(100);
    private Collection<Region> m_RootRegions = new Collection<Region>();
    private bool m_NeedRefresh;

    public override void Add(ProviderBase provider) {
      if (provider == null)
        throw new ArgumentNullException("provider");

      if (!(provider is RegionProvider))
        throw new ArgumentException(Translator.Error_ProviderMustImplementRegionProvider, "provider");

      m_NeedRefresh = true;

      base.Add(provider);
    }

    private void RefreshAll() {
      if (m_NeedRefresh) {
        m_RegionById.Clear();
        m_RootRegions.Clear();
        Collection<IRawRegion> rawRegions = new Collection<IRawRegion>();

        foreach (RegionProvider provider in this) {
          foreach (IRawRegion rawRegion in provider.Regions) {
            Region region = new Region(rawRegion);
            if (m_RegionById.ContainsKey(rawRegion.Id))
              throw new DataSourceException(String.Format(CultureInfo.InvariantCulture, Translator.Error_RegionAlreadyInCache, region.Id));

            m_RegionById.Add(region.Id, region);
            rawRegions.Add(rawRegion);
          }
        }

        foreach (IRawRegion rawRegion in rawRegions) {
          if (String.IsNullOrEmpty(rawRegion.ParentId)) {
            Region region = (Region)m_RegionById[rawRegion.Id];
            m_RootRegions.Add(region);
          } else {
            Region parent = (Region)m_RegionById[rawRegion.ParentId];
            Region child = (Region)m_RegionById[rawRegion.Id];
            child.Parent = parent;
            parent.InternalChildren.Add(child);
          }
        }

        m_NeedRefresh = false;
      }
    }

    public IList<Region> RootRegions {
      get {
        RefreshAll();
        return m_RootRegions;
      }
    }

    public IEnumerable<Region> Regions {
      get {
        RefreshAll();
        foreach (Region region in m_RegionById.Values)
          yield return region;
      }
    }

    public Region GetRegionById(string regionId) {
      RefreshAll();
      return (Region)m_RegionById[regionId];
    }

    public IEnumerable<Region> GetRegions(RegionCriteria criteria) {
      foreach (Region region in Regions) {
        if (criteria.Evaluate(region))
          yield return region;
      }
    }
  }
}
